package cn.donting.web.desktop.core.servlet.websocket;

import cn.donting.web.desktop.core.Application;
import cn.donting.web.desktop.core.listener.AppListener;
import cn.donting.web.desktop.top.AppContext;
import org.eclipse.jetty.websocket.jsr356.server.ServerContainer;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.web.context.ServletContextAware;

import javax.servlet.ServletContext;
import javax.websocket.DeploymentException;
import javax.websocket.server.ServerEndpoint;
import javax.websocket.server.ServerEndpointConfig;

import org.eclipse.jetty.websocket.jsr356.server.ServerEndpointMetadata;
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
import org.eclipse.jetty.websocket.server.NativeWebSocketConfiguration;
import org.eclipse.jetty.websocket.server.NativeWebSocketServletContainerInitializer;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;


/**
 * app websocket 注册器
 * EndpointPath 需加上 /appId  /appId/EndpointPath 区分不同app
 * Endpoint 直接走 server 容器
 */
@Component
public class AppWebSocketRegister implements ServletContextAware, ApplicationContextAware, AppListener {
    private ServletContext servletContext;
    private ServerContainer serverContainer;
    private ApplicationContext applicationContext;
    private NativeWebSocketConfiguration nativeWebSocketConfiguration;

    private final HashMap<Application, List<AppServerEndpointConfig>> endpointConfigs=new HashMap();

    @Override
    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
        if (this.serverContainer == null) {
            this.serverContainer = (ServerContainer) servletContext.getAttribute(WebSocketServerContainerInitializer.ATTR_JAVAX_SERVER_CONTAINER);
            this.nativeWebSocketConfiguration = (NativeWebSocketConfiguration) servletContext.getAttribute(NativeWebSocketServletContainerInitializer.ATTR_KEY);
        }
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 添加端点到 serverContainer
     * @see org.eclipse.jetty.websocket.jsr356.server.ServerContainer#addEndpoint(ServerEndpointConfig)
     * @param application
     */
    @Override
    public void afterStart(Application application) {
        try {
            AppContext appContext = application.getAppContext();
            String[] endpointBeanNames = appContext.getBeanNamesForAnnotation(ServerEndpoint.class);
            ArrayList<AppServerEndpointConfig> endpointConfigList=new ArrayList<>();
            for (String endpointBeanName : endpointBeanNames) {
                Class<?> endpoint = appContext.getType(endpointBeanName);
                ServerEndpoint serverEndpoint = endpoint.getDeclaredAnnotation(ServerEndpoint.class);
                AppServerEndpointConfig appServerEndpointConfig=new AppServerEndpointConfig(application,serverContainer,endpoint,serverEndpoint);
                //添加 Endpoint
                serverContainer.addEndpoint(appServerEndpointConfig);
                endpointConfigList.add(appServerEndpointConfig);
            }
            endpointConfigs.put(application,endpointConfigList);
        } catch (DeploymentException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void beforeStop(Application application) {
        //移除容器  ServerEndpoint
        List<AppServerEndpointConfig> remove = endpointConfigs.remove(application);
        for (AppServerEndpointConfig appServerEndpointConfig : remove) {
            String endpointPath = getEndpointPath(appServerEndpointConfig);
            nativeWebSocketConfiguration.removeMapping(endpointPath);
        }

    }

    /**
     * 获取 EndpointPath
     *  @see org.eclipse.jetty.websocket.jsr356.server.ServerContainer#addEndpoint(ServerEndpointMetadata)
     * @param appServerEndpointConfig
     * @return
     */
    private String getEndpointPath(AppServerEndpointConfig appServerEndpointConfig){
        return "uri-template|"+appServerEndpointConfig.getPath();
    }

}
